#ifndef __crowd_dynamicsH__
#define __crowd_dynamicsH__

#include "kernel.h"
#include "wtftypes.h"
#include "physics.h"
#include "aux-math.h"
#include "ai_behaviour.h"

namespace WtfEngine
{
	/**
	 * Crowd member interface. Crowd members cause discomfort to mobile actors which have
	 * the crowd dynamics behaviour applied, causing them to avoid the crowds.
	 **/
	class ICrowdMember: public virtual IGcObject {
		GC_INTERFACE(ICrowdMember);

	private:
		typedef std::list<ICrowdMember::tRef>	tCrowdList;

		static tCrowdList	gCrowdList;

	public:
		virtual void Init();
		virtual void Destroy();

		virtual tPosition getPosition() const = 0;

		/// Returns the object's resistance to deviation from its goal path.
		virtual tScalar getResistance() const = 0;

		/// Returns the discomfort generated by this object for the specified actor, at the
		/// specified position.
		virtual tScalar getDiscomfort(const IMobileActor::tRef& rActor, const tPosition& vPos) const = 0;

		/// Returns the total discomfort at the specified loaction
		static tScalar _getDiscomfort(const IMobileActor::tRef& rActor, const tPosition& vPos);
	};


	/**
	 * Generic crowd member - mainly used to test the crowd dynamics.
	 **/
	class CrowdMember : public virtual ICrowdMember, public virtual IMobileActor, public Physical
	{
	private:
		tScalar		mIntimidation, mResistance;
		tPosition	mGoalPosition;

	public:
		CrowdMember(const WtfGraphics::GraphicsData::tCacheRef& rModel,
			const PhysicalModel::tCacheRef& rPhys, tScalar mq,
			tScalar intimidation = 10.0, tScalar resistance = 0.0000000001);

		// ICrowdMember functions
		tScalar getDiscomfort(const IMobileActor::tRef& rActor, const tPosition& vPos) const;
		
		tScalar getResistance() const{
			return mResistance;
		};
		
		// IMobileActor functions
		void Update();
		
		tPosition getPosition() const {
			return Physical::getPosition();
		};
		Orientation3D getOrientation() const{
			return Physical::getOrientation();
		};
		tDirection getVelocity() const {
			return Physical::getVelocity();
		};
		void setVelocity(const tDirection& v) {
			Physical::setVelocity(v);
		};

		tPosition getGoalPosition() const {
			return mGoalPosition;
		};
		tScalar getGoalRadius() const {
			return 1.0;
		};


		static void Test();
		
	protected:
		// Returns the discomfort generated by this object at
		// given position in the object-local field
		tScalar _GetDiscomfort(const tPosition& pos);
	};

	namespace Behaviours {
		class CrowdBehaviour : public GoalMotion
		{
		public:
			CrowdBehaviour(const StringPool::Entry& sName = "ai_CrowdBehaviour"): GoalMotion(sName) {};

			virtual bool Evaluate(const IMobileActor::tRef& rActor, const tPosition& vGoal, tDirection& vDesiredVelocity);

			/// Interface to data manager
			static WtfEngine::IDataObject * Load(const StringPool::Entry& sName) {
				return new CrowdBehaviour(sName);
			};
			DATA_LOADABLE(CrowdBehaviour, sizeof(CrowdBehaviour));
		};
	};
};

#endif
